<?php
declare (strict_types = 1);

namespace app\admin\controller\projects;

use app\admin\controller\AuthController;
use app\admin\model\project\ProjectColumns;
use app\admin\model\project\Projects;
use app\admin\model\project\ProjectTaskJobs;
use app\admin\model\project\ProjectTaskLogs;
use app\admin\model\project\ProjectTasks;
use app\admin\model\project\Swimlanes;
use app\admin\model\system\SystemMenus;
use app\admin\model\system\SystemRole;
use bbweb\services\UtilService as Util;
use bbweb\utils\Avatar;
use think\facade\Config;
use think\facade\Db;
use think\Request;

class Index extends AuthController
{
    /**
     * 显示列表
     *
     * @param  \think\Request  $req
     * @return \think\Response
     */
    public function index(Request $req)
    {
        $statuss = Config::get('hello.pro_status', [0=>'待启动', 1=>'施工中', 2=>'已完成']);
        $sonAuth = SystemMenus::getSonAuth($req->controller(), $req->action(),array_keys($this->auth));
        if(isset($sonAuth['all'])) {
            $types = Db::name('project_types')->column('name', 'id');
            $users = SystemRole::roleAdmin();
        } else {
            $adminInfo = $this->adminInfo;
            $roleid = $adminInfo['roleid']??0;
            $groupid = SystemRole::where('id', $roleid)->value('pid');
            $role = SystemRole::where('id',$groupid)->find();
            $types = Db::name('project_types')->where('group', $groupid)->column('name', 'id');
            $users = Db::name('system_admin')->where('roleid','IN', $role['path'])->where('is_del', 0)->column('id,real_name','id');
        }
        if ($req->isAjax()) {
            $data = [];
            $page = $req->param('page/d', 1);
            $limit = $req->param('limit/d', 15);
            $role_user = $req->param('role_user','');

            $query = Db::name('projects')->alias('a')
                ->leftJoin('system_admin u', 'u.id = a.uid')
                ->where('a.is_delete', 0);
            if (!is_null($role_user) && strlen($role_user)) {
                $role_user = explode('-',$role_user);
                if($role_user[0] == 'r') {
                    $role_id = intval($role_user[1]);
                    $a_types = Db::name('project_types')->where('group', $role_id)->column('name', 'id');
                    $query->where('a.type','in',array_keys($a_types));
                } else {
                    $user_id = intval($role_user[1]);
                    $query->where(function ($query) use($user_id) {
                        $query->where('FIND_IN_SET(:uid,`a`.`owner_id`)',['uid' => $user_id])
                            ->whereOr('FIND_IN_SET(:uid,`a`.`audit_id`)',['uid' => $user_id])
                            ->whereOr('FIND_IN_SET(:uid,`a`.`teams`)',['uid' => $user_id]);
                    });
                }
            }
            $query->field('a.*, u.real_name as account');
            // 条件搜索
            $status = $req->param('status');
            if (!is_null($status) && strlen($status)) {
                $query->where('a.status','=',$status);
            }
            $type = $req->param('type');
            if (!is_null($type) && strlen($type)) {
                $query->where('a.type','=',$type);
            }
            if(!isset($sonAuth['all'])) {
                $query->where('a.type','in',array_keys($types));
            }
            $sys = $req->param('sys');
            if (!is_null($sys) && strlen($sys)) {
                $query->where('a.sys','=',$sys);
            }
            $name = $req->param('name');
            if (!is_null($name) && strlen($name)) {
                $query->where('a.name','like',"%$name%");
            }

            $query->order('a.id DESC');
            $data['count'] = $query->count('a.id');
            $data['data'] = $query->page($page,$limit)->select()->toArray();

            $data['code'] = 0;
            $data['msg'] = '';
            foreach ($data['data'] as &$val) {
                $val['statustext'] = $statuss[$val['status']] ?? '--/--';
                $val['typetext'] = $types[$val['type']] ?? '--/--';
                $val['progress_list'] = $val['progress_list'] ? array_merge(json_decode($val['progress_list'], true)) : [];
                $progress = get_progress($val['start_at'], $val['end_at'], $val['finish_at']);
                $val['progress'] = $progress['progress'];
                $val['progress_color'] = $progress['color'];
                $val['create_at'] = $val['create_at'] ? date('Y-m-d',$val['create_at']) : '--/--';
                $val['finish_at'] = $val['finish_at'] ? date('Y-m-d',$val['finish_at']) : '--/--';
                $val['start_at'] = $val['start_at'] ? date('Y-m-d',$val['start_at']) : '--/--';
                $val['end_at'] = $val['end_at'] ? date('Y-m-d',$val['end_at']) : '--/--';
                $val['account'] = $val['account'] ?? '--/--';
            }
            return json($data);
        }

        // 显示页面
        $this->assign('statuss', $statuss);
        $this->assign('sonAuth', $sonAuth);
        $this->assign('types', $types);
        $this->assign('users', $users);
        return $this->fetch();
    }

    /**
     * 显示列表
     *
     * @param  \think\Request  $req
     * @return \think\Response
     */
    public function rate(Request $req)
    {
        if ($req->isAjax()) {
            $groups = SystemRole::getSelect(0,2);
            $data = [];
            // 条件搜索
            $start_at = $req->param('start_at');
            if (is_null($start_at) || strlen($start_at)==0) {
                $start_at = date('Y-m');
            }
            $start = strtotime($start_at);
            $end = strtotime(date('Y-m-t',$start).' 23:59:59');
            $query = Db::name('system_admin')->alias('a')
                ->leftJoin('project_tasks p', 'p.owner_id=a.id and p.is_delete=0 and p.status=2 and p.rate_at >= '.$start.' and p.rate_at <= '.$end)
                ->field('a.*,ifnull(round(sum(p.rate_work),1),0) as rate_work,ifnull(round(sum(p.rate_audit),1),0) as rate_audit,ifnull(round(sum(p.rate_punish),1),0) as rate_punish,ifnull(sum(p.rate_total),0) as rate_total');

            $roleid = $req->param('roleid');
            if (!is_null($roleid) && strlen($roleid)) {
                $path = Db::name('system_role')->where('id',$roleid)->value('path');
                $query->where('a.roleid','in',$path);
            }
            $query->group('a.id');
            $query->order('a.roleid');
            $data['count'] = 0;
            $data['data'] = $query->select()->toArray();

            $data['code'] = 0;
            $data['msg'] = '';
            foreach ($data['data'] as &$val) {
                $val['rate_total'] = round($val['rate_total'],1);
                $val['rate_work'] = round($val['rate_work'],1);
                $val['rate_audit'] = round($val['rate_audit'],1);
                $val['rate_punish'] = round($val['rate_punish'],1);
                $val['group'] = isset($groups[$val['roleid']]) ? $groups[$val['roleid']] : '--/--';
            }

            return json($data);
        }
        $sonAuth = SystemMenus::getSonAuth($req->controller(), $req->action(),array_keys($this->auth));
        $groups = SystemRole::getSelect(0,0);
        // 显示页面
        $this->assign('sonAuth', $sonAuth);
        $this->assign('groups', $groups);
        return $this->fetch();
    }
    /**
     * 分配器
     * @param Request $req
     * @return string
     * @throws \Exception
     */
    public function show(Request $req)
    {
        $op = $req->param('op', 'basic');
        switch ($op) {
            case 'board':
                return $this->showBoard($req);
            case 'check':
                return $this->showCheck($req);
            case 'show'://查看任务
                return $this->showTask($req);
            default://概览
                return $this->showBasic($req);
        }
    }

    /**
     * @param Request $req
     */
    private function showCheck(Request $req)
    {
        $id = intval($req->param('id/d'));
        $timestamp = intval($req->param('timestamp/d'));
        if(!$id || !$timestamp) $this->error('参数错误');
        $pro = Projects::get($id);
        if(!$pro) $this->error('参数错误');
        if($pro['update_at'] > $timestamp) {
            return json(['code'=>1,'msg'=>'ok']);
        }
        return json(['code'=>0,'msg'=>'ok']);
    }
    /**
     * 任务概览
     * @param Request $req
     * @return string
     * @throws \Exception
     */
    private function showBasic(Request $req)
    {
        $id = intval($req->param('id/d'));
        if(!$id) $this->error('参数错误');
        $uid = (int) $this->adminId;
        $pro = Projects::get($id);
        if(!$pro) $this->error('参数错误');
        if($pro['is_delete']) $this->exception('项目已删除');

        $pro['images'] = !empty($pro['images']) ? explode('|',$pro['images']) : [];
        $statuss = Config::get('hello.pro_status', [0=>'待启动', 1=>'施工中', 2=>'已完成']);
        $pro['statustext'] = $statuss[$pro['status']] ?? '--/--';
        $this->assign('pro', $pro);
        $this->assign('uid', $uid);
        $account = $pro['uid'] ? Db::name('system_admin')->where('id',$pro['uid'])->value('real_name') : '--/--';
        $owners = $pro['owner_id'] ? Db::name('system_admin')->where('id', 'IN',$pro['owner_id'])->column('real_name', 'id') : ['--/--'];
        $audits = $pro['audit_id'] ? Db::name('system_admin')->where('id', 'IN',$pro['audit_id'])->column('real_name', 'id') : ['--/--'];
        $teams = $pro['teams'] ? Db::name('system_admin')->where('id', 'IN', $pro['teams'])->column('real_name', 'id') : ['--/--'];

        $events = ProjectTaskLogs::where('project_id', $id)->order('id DESC')->limit(20)->select();

        $user_level = $this->adminInfo['level']==0 && $this->adminInfo['id']==-1 ? 1 : 0;
        $sonAuth = SystemMenus::getSonAuth($req->controller(), 'index',array_keys($this->auth));
        $this->assign('sonAuth', $sonAuth);

        $this->assign('account', $account);
        $this->assign('owners', $owners);
        $this->assign('teams', $teams);
        $this->assign('audits', $audits);
        $this->assign('events', $events);
        $this->assign('user_level', $user_level);
        return $this->fetch('info');
    }

    /**
     * 操纵台
     * @param $req
     * @return string
     * @throws \Exception
     */
    private function showBoard($req)
    {
        $id = intval($req->param('id/d'));
        if(!$id) $this->error('参数错误');
        $uid = (int) $this->adminId;
        $pro = Projects::get($id);
        if(!$pro) $this->error('参数错误');
        if($pro['is_delete']) $this->exception('项目已删除');

        $pro['images'] = !empty($pro['images']) ? explode('|',$pro['images']) : [];
        $statuss = Config::get('hello.pro_status', [0=>'待启动', 1=>'施工中', 2=>'已完成']);
        $deeps = Config::get('hello.pro_deeps', [1=>'低', 2=>'中', 3=>'高', 4=>'紧急']);
        $pro['statustext'] = $statuss[$pro['status']] ?? '--/--';
        $collapsed = Db::name('project_user_event')->where('project_id', $pro['id'])->where('uid', $uid)->where('event','collapsed')->find() ? 1 : 0;
        $owner_id_only = Db::name('project_user_event')->where('project_id', $pro['id'])->where('uid', $uid)->where('event','only')->find() ? $uid : 0;
        $this->assign('pro', $pro);
        $this->assign('uid', $uid);
        $this->assign('collapsed', $collapsed);
        $this->assign('owner_id_only', $owner_id_only);
        $sonAuth = SystemMenus::getSonAuth($req->controller(), 'index',array_keys($this->auth));
        $this->assign('sonAuth', $sonAuth);

        $users = [];
        $swimlanes = Swimlanes::getSwimlanes($pro['id']);
        $columns = ProjectColumns::getColumn($pro['id']);
        $avatar = new Avatar();
        $tasks = [];
        foreach ($swimlanes as $sv) {
            $tasks['swimlanes'][$sv['id']]['swim'] = $sv;
            $tasks['swimlanes'][$sv['id']]['column'] = 0;//泳道任务数
            foreach ($columns as $cv) {
                $tasks['column'.$cv['position']] = $pro['progress_list'][$cv['position']]['total'] ?? 0;
                $tasks['swimlanes'][$sv['id']]['columns'][$cv['position']] = $cv;
                $tasks['swimlanes'][$sv['id']]['columns'][$cv['position']]['column'] = 0;//栏目任务数
                $tasks['swimlanes'][$sv['id']]['columns'][$cv['position']]['lists'] = [];
            }
        }
        $data = ProjectTasks::getTasks($pro['id'], $owner_id_only);
        foreach ($data as $key=>$val) {
            if(!isset($users[$val['owner_id']])) {
                $user = Db::name('system_admin')->where('id', $val['owner_id'])->field('id,real_name')->find();
                if($user) {
                    $user['owner_avatar'] = $avatar->render($user['real_name']);
                    $users[$val['owner_id']] = $user;
                } else {
                    $users[$val['owner_id']] = ['id'=>0,'real_name'=>'--/--','owner_avatar'=>'rgb(176 176 176)'];
                }
            }
            $val['owner_name'] = $users[$val['owner_id']]['real_name'];
            $val['owner_avatar'] = $users[$val['owner_id']]['owner_avatar'];
            $val['estimated'] = $val['time_spent'] .'/'. $val['time_estimated'] .'h';
            $val['task_links'] = 0;
            $val['end_date'] = $val['end_at'] ? date('Y/m/d', $val['end_at']) : '';
            $val['deep_name'] = $deeps[$val['deep']];
            $tasks['swimlanes'][$val['swimlane_id']]['columns'][$val['column_id']]['lists'][] = $val;
            $tasks['swimlanes'][$val['swimlane_id']]['column'] += 1;
            $tasks['swimlanes'][$val['swimlane_id']]['columns'][$val['column_id']]['column'] += 1;
        }
        $user_level = $this->adminInfo['level']==0 && $this->adminInfo['id']==-1 ? 1 : 0;
        $this->assign('user_level', $user_level);
        $this->assign('tasks', $tasks);
        return $this->fetch('show');
    }

    /**
     * 查看任务
     * @param Request $req
     * @return string
     * @throws \Exception
     */
    private function showTask(Request $req)
    {
        $id = intval($req->param('id/d'));
        $task_id = intval($req->param('task_id/d'));
        if(!$id || !$task_id) $this->error('参数错误');
        $uid = (int) $this->adminId;
        $pro = Projects::get($id);
        if(!$pro) $this->error('参数错误');
        if($pro['is_delete']) $this->exception('项目已删除');
        $task = ProjectTasks::find(['id'=>$task_id]);
        if(!$task || $task['is_delete']) $this->error('项目不存在或已删除','',-1);
        $statuss = Config::get('hello.pro_status', [0=>'待启动', 1=>'施工中', 2=>'已完成']);
        $pro['statustext'] = $statuss[$pro['status']] ?? '--/--';
        $this->assign('pro', $pro);
        $this->assign('uid', $uid);
        //创建者
        $account = $pro['uid'] ? Db::name('system_admin')->where('id',$task['uid'])->value('real_name') : '--/--';
        //接受者
        $owner_name = $pro['owner_id'] ? Db::name('system_admin')->where('id',$task['owner_id'])->value('real_name') : '--/--';
        $audit = $pro['audit_id'] ? Db::name('system_admin')->where('id',$pro['audit_id'])->value('real_name') : '--/--';
        $events = ProjectTaskLogs::where('task_id', $task_id)->where('project_id', $id)->order('id DESC')->select();
        $jobs = ProjectTaskJobs::where('task_id', $task_id)->where('project_id', $id)->order('id DESC')->select();
        $columns = ProjectColumns::getColumn($pro['id']);
        $task['column_name'] = $columns[$task['column_id']] ? $columns[$task['column_id']]['title'] : '--/--';

        $time_work = '--/--';
        if($task['status'] > 0 ) {
            if( $task['time_estimated'] > $task['time_spent'] ) {
                $time_work = '提前'. round($task['time_estimated'] - $task['time_spent'], 1). 'h';
            } else if( round($task['time_estimated']) == round($task['time_spent']) ) {
                $time_work = '按时完成';
            } else {
                $time_work = '超时'. round($task['time_spent'] - $task['time_estimated'], 1) .'h';
            }
        }
        $task['time_work'] = $time_work;

        $deeps = Config::get('hello.pro_deeps', [1=>'低', 2=>'中', 3=>'高', 4=>'紧急']);
        $task['deep_name'] = $deeps[$task['deep']];
        $task['create_date'] = $task['create_at'] ? date('Y-m-d H:i',$task['create_at']) : '--/--';
        $task['start_date'] = $task['start_at'] ? date('Y-m-d H:i',$task['start_at']) : '--/--';
        $task['end_date'] = $task['end_at'] ? date('Y-m-d H:i',$task['end_at']) : '--/--';

        $this->assign('account', $account);
        $this->assign('owner_name', $owner_name);
        $this->assign('audit', $audit);
        $this->assign('events', $events);
        $this->assign('jobs', $jobs);
        $this->assign('task', $task);
        return $this->fetch('task_info');
    }

    /**
     * 创建资源.
     *
     * @param  \think\Request  $req
     * @return \think\Response
     */
    public function add(Request $req)
    {
        if($req->isPost()) {
            $data = Util::postMore([
                'name',
                'description',
                ['images', ''],
                ['type', 0],
                ['sys', 0]
            ]);
            if (!$data['name']) $this->error('请输入项目名称');
            if (!$data['description']) $this->error('请输入项目描述');
            if (!$data['type']) $this->error('请选择项目分类');

            if($this->adminId > 0) $data['uid'] = $this->adminId;
            $data['create_at'] = time();
            $data['update_at'] = time();

            Projects::beginTrans();
            try {
                $res = Projects::create($data);
                if($res && $res->id) {
                    $project_id = $res->id;
                    $columns = Config::get('hello.columns', ['待处理','准备做','正在做','已完成']);
                    $res = ProjectColumns::addColumn($project_id, $columns);
                    if(!$res || !$tool = Projects::toolTask($project_id) ) {
                        throw new \think\Exception('新项目对应数据写入失败！');
                    }
                } else {
                    throw new \think\Exception('新项目写入失败！');
                }
                Projects::commitTrans();
            } catch(\Exception $e) {
                Projects::rollbackTrans();
                $this->error($e->getMessage());
            }
            return json(['code'=>1, 'msg'=>'操作成功']);
        }
        $adminInfo = $this->adminInfo;
        $roleid = $adminInfo['roleid']??0;
        $groupid = SystemRole::where('id', $roleid)->value('pid');
        $types = Db::name('project_types')->where('group', $groupid)->column('name', 'id');
        if($this->adminId == -1 ) {
            $types = Db::name('project_types')->column('name', 'id');
        }
        $this->assign('types', $types);
        return $this->fetch();
    }

    /**
     * 更新资源
     *
     * @param  \think\Request  $req
     * @return \think\Response
     */
    public function edit(Request $req)
    {
        $id = intval($req->param('id/d'));
        if(!$id) $this->error('参数错误','',-1);
        $pro = Projects::get($id);
        if(!$pro) $this->error('参数错误','',-1);
        if($req->isPost()) {
            $data = Util::postMore([
                'name',
                'description',
                ['images', ''],
                ['type', 0],
                ['sys', 0]
            ]);
            if (!$data['name']) $this->error('请输入项目名称');
            if (!$data['description']) $this->error('请输入项目描述');
            if (!$data['type']) $this->error('请选择项目分类');

            if($this->adminId > 0) $data['uid'] = $this->adminId;
            $data['update_at'] = time();

            $res = Projects::where('id', $id)->update($data);
            if(!$res) {
                $this->error('修改失败');
            }
            return json(['code'=>1, 'msg'=>'操作成功']);
        }
        $adminInfo = $this->adminInfo;
        $roleid = $adminInfo['roleid']??0;
        $groupid = SystemRole::where('id', $roleid)->value('pid');
        $types = Db::name('project_types')->where('group', $groupid)->column('name', 'id');
        if($this->adminId == -1 ) {
            $types = Db::name('project_types')->column('name', 'id');
        }
        $this->assign('types', $types);

        $pro['images_list'] = !empty($pro['images']) ? explode('|',$pro['images']) : [];
        $this->assign('pro', $pro);
        return $this->fetch();
    }

    /**
     * 删除指定资源
     *
     * @param  int  $id
     * @return \think\Response
     */
    public function del(Request $req)
    {
        $id = intval($req->param('id/d'));
        if(!$id) $this->error('参数错误');
        $pro = Projects::get($id);
        if($pro->status > 0) $this->error('已启动的项目不能删除');
        $pro->is_delete = 1;
        $pro->save();
        $this->success('删除成功');
    }

    /**
     * 项目人员分配+启动控制
     * @param Request $req
     * @return string
     * @throws \Exception
     */
    public function dispatch(Request $req)
    {
        $id = intval($req->param('id/d'));
        $op = $req->param('op', 's');
        if(!$id) $this->error('参数错误','',-1);
        $pro = Projects::get($id);
        if(!$pro) $this->error('参数错误','',-1);
        if($req->isPost()) {
            if($op == 'start') {//启动
                $data = Util::postMore([
                    ['start_at', ''],
                    ['end_at', '']
                ]);
                $data['start_at'] = preg_match("/^\d{4}-\d{1,2}-\d{1,2}$/s",$data['start_at']) ? strtotime($data['start_at']) : 0;
                $data['end_at'] = preg_match("/^\d{4}-\d{1,2}-\d{1,2}$/s",$data['end_at']) ? strtotime($data['end_at']) : 0;
                if (!$data['start_at']) $this->error('请设置项目启动时间');
                if (!$data['end_at']) $this->error('请设置预计完成时间');
                $data['status'] = 1;
            } else if($op == 'user') {
                //负责人
                $owners = $req->param('owner_id',[]);
                if(!empty($owners)) foreach($owners as $key=>$val) {
                    if(!$val) unset($owners[$key]);
                }
                $data['owner_id'] = implode(',', $owners);
                //审计
                $audits = $req->param('audit_id',[]);
                if(!empty($audits)) foreach($audits as $key=>$val) {
                    if(!$val) unset($audits[$key]);
                }
                $data['audit_id'] = implode(',', $audits);
                //成员
                $teams = $req->param('team',[]);
                if(!empty($teams)) foreach($teams as $key=>$val) {
                    if(!$val || in_array($val, $owners) || in_array($val, $audits)) unset($teams[$key]);
                }
                $data['teams'] = implode(',', $teams);

                if (!$data['owner_id']) $this->error('请选择项目负责人');
                if (!$data['audit_id']) $this->error('请选择项目审计人');
            }
            if($this->adminId > 0) $data['uid'] = $this->adminId;
            $data['update_at'] = time();

            $res = Projects::where('id', $id)->update($data);
            if(!$res) {
                $this->error('修改失败');
            }
            return json(['code'=>2, 'msg'=>'操作成功']);
        }
        if($op == 'start') {//启动
            if(!$pro['owner_id']) $this->error('未分配项目负责人不能启动项目','',-1);
            $pro['start_at'] = $pro['start_at'] ? date('Y-m-d', $pro['start_at']) : '';
            $pro['end_at'] = $pro['end_at'] ? date('Y-m-d', $pro['end_at']) : '';
            $this->assign('pro', $pro);
            return $this->fetch('dispatch_start');
        } else if($op == 'user') {
            $pro['owners'] = explode(',', $pro['owner_id']);
            $pro['teams'] = explode(',', $pro['teams']);
            $pro['audits'] = explode(',', $pro['audit_id']);
            $this->assign('pro', $pro);
            $users = SystemRole::roleAdmin();
            $this->assign('users', $users);
            return $this->fetch('dispatch_user');
        }
        $this->error('错误操作！','',-1);
    }
}
